package control;
import gui.DialogCollection;
import gui.GUI;
import gui.menu.HighscoreMenu;

import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.EventListener;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JOptionPane;

import challengesManager.ChallengeManager;
import challengesManager.CharacterSearchManager;
import challengesManager.ElementCountManager;
import challengesManager.FallingBoxManager;
import challengesManager.FindTheSameManager;
import data.ChallengeData;
import data.HighScores;
import data.HighscoreEntry;
import data.Options;
import data.Player;


public class Control implements EventListener {

	KeyInputManager kim;
	GUI gui;
	Options options;
	HighScores highscores;
	Timer timer;
	Player[] players;

	List<ChallengeManager> challmanager;

	private int aktchall;

	public MainMenuManager mainManager;
	public OptionsMenuManager optionsManager;
	public SelectPlayersMenuManager selectPlayersManager;
	public HighscoreMenuManager highscoreManager;

	public Control(){
		challmanager = new ArrayList<ChallengeManager>();

		options = IOManager.loadOptions();
		highscores = IOManager.loadHighscores();

		players = options.getPlayers();

		kim = new KeyInputManager(this);

		mainManager = new MainMenuManager(this);
		optionsManager = new OptionsMenuManager(this);
		highscoreManager = new HighscoreMenuManager(this);
		selectPlayersManager = new SelectPlayersMenuManager(this);


		gui = new GUI(this);

		gui.addKeyListener(kim);
		gui.addFocusListener(new FocusAdapter() {

			@Override
			public void focusLost(FocusEvent arg0) {

				gui.requestFocus();

			}

		});

		aktchall = -1;
	}

	public Options getOptions(){
		if (options != null){
			return options;
		}else{
			System.out.println("There is no Options object!");
			System.exit(0);
			return options;
		}
	}


	public ChallengeManager createChallengeManager( int i){
		switch (i){
		case 0:return new ElementCountManager(this, options.getChallenges()[i]);
		case 1:return new FallingBoxManager(this, options.getChallenges()[i]);
		case 2:return new CharacterSearchManager(this, options.getChallenges()[i]);
		case 3:return new FindTheSameManager(this, options.getChallenges()[i]);
		case 4:return null;
		default: System.out.println( "Wrong Index for Challenge Manager"); System.exit(0);
		}
		return null;
	}

	class MyTimerTask extends TimerTask{
		Control control;
		public MyTimerTask(Control c){
			control = c;
		}

		@Override
		public void run() {
			control.checks();

		}
	}

	public void checks(){
		if (challmanager.get(aktchall) != null){
			switch (challmanager.get(aktchall).getState()){
			case ChallengeManager.STATE_RUNNING: break;
			case ChallengeManager.STATE_ERROR: JOptionPane.showMessageDialog(gui,
					"Die Challenge hat einen Fehler entdeckt! Das Programm wird geschlossen!",
					"Error",
					JOptionPane.ERROR_MESSAGE); break;
			case ChallengeManager.STATE_FINISHED: startNext(); break;
			case ChallengeManager.STATE_LOADED_AND_READY: challmanager.get(aktchall).start(); break;
			case ChallengeManager.STATE_LOADING: break;
			case ChallengeManager.STATE_PAUSED: break;
			case ChallengeManager.STATE_UNDEFINED: break;
			}
		}else{
			aktchall++;
			checks();
		}
	}

	public ChallengeManager getCurChallMan(){
		if (aktchall == -1 || challmanager.isEmpty() || aktchall >= challmanager.size()) return null;
		return challmanager.get(aktchall);
	}

	private void startNext(){
		challmanager.get(aktchall).disposeGui();
		if( aktchall < challmanager.size() - 1){
			aktchall++;
			if(challmanager.get(aktchall) == null){ 
				timer.cancel();
			}else{
				challmanager.get(aktchall).initGui(gui.gamepanel.getChallengePanel());
				gui.gamepanel.setCaption(challmanager.get(aktchall).getData().getName());
			}

		}else{
			aktchall = -1;
			timer.cancel();

			//get max points => max
			int max = players[0].getPoints();
			for (Player player : players){
				if(player.isEnabled()){
					if (max < player.getPoints()){
						max = player.getPoints();
					}
				}
			}
			boolean[] gewinner = new boolean[players.length];

			String gewinnstr = "Winner: ";

			for (int j=0; j < players.length; j++){
				if(players[j].getPoints() == max){
					gewinner[j] = true;
				}else{
					gewinner[j] = false;
				}
			}

			int numberwinner = 0;
			for (int j=0; j < players.length; j++){
				if(gewinner[j] && players[j].isEnabled()){
					if(numberwinner != 0){
						gewinnstr += ", ";
					}
					gewinnstr += players[j].getName();
					numberwinner++;

				}
			}

			DialogCollection.showMessageDialog(gewinnstr);
			if(!checkForHighScore())gui.showMenu("MainMenu");
			else{
				gui.highscoremenu.selectDifficulty(options.getDifficulty());
				gui.showMenu("HighscoreMenu");
			}
		}
	}

	public void newGame(){

		gui.playeroptions.init(players,selectPlayersManager);
		gui.showMenu("PlayerOptions");


	}

	public void startGames(){

		ArrayList<Player> activePlayers = new ArrayList<Player>();
		for (int i = 0; i < players.length; i++) {
			if(players[i].isEnabled()){
				activePlayers.add(players[i]);
				players[i].setPoints(0);
			}
		}
		challmanager.clear();

		for(int i = 0; true; ++i){
			ChallengeManager chm = createChallengeManager(i);
			if(chm == null)break;
			if(chm.getData().getRounds() == 0)continue;
			else challmanager.add(chm);
		}

		if(challmanager.isEmpty()){
			DialogCollection.showMessageDialog("You have disabled all challenges. Go to Options menu and set at least one challenge to play.");
			this.abortGames();
			return;
		}
		gui.gamepanel.init(activePlayers.toArray(new Player[0]));
		Collections.shuffle(challmanager);
		Collections.shuffle(activePlayers);

		aktchall = 0;
		timer = new Timer();
		MyTimerTask task = new MyTimerTask(this);

		gui.gamepanel.setCaption(challmanager.get(aktchall).getData().getName());
		gui.showMenu("GamePanel");
		gui.requestFocus();
		gui.gamepanel.updateScores();

		challmanager.get(aktchall).initGui(gui.gamepanel.getChallengePanel());
		timer.schedule(task, 0, 10);
	}


	public HighScores getHighscores(){
		return highscores;
	}

	public void playerHasPressed(Player pl) {
		gui.gamepanel.playerHasPressed(pl);

	}

	public void updateScores() {
		gui.gamepanel.updateScores();
	}
	
	public void enableBuzzing(){
		kim.playerActionIsProcessed();
	}
	
	public void disableBuzzing(){
		kim.disableBuzzing();
	}

	public boolean checkForHighScore(){
		//count rounds
		ChallengeData[] data = options.getChallenges();
		int rounds = 0;

		for (int i = 0; i < data.length; i++) {
			rounds += data[i].getRounds();
		}

		if (rounds < HighScores.CHANCE_FOR_HIGHSCORE_MIN_SC) return false;
		for (int i = 0; i < players.length; i++) {
			if(players[i].isEnabled()){
				HighscoreEntry tmp = new HighscoreEntry(players[i].getName(), options.getDifficulty(),(int)((float)(players[i].getPoints()*100)/rounds),Calendar.getInstance());
				highscores.add(tmp);
			}
		}
		IOManager.saveHighscores(highscores);
		return true;
	}

	public void abortGames() {
		if(getCurChallMan() != null){
			timer.cancel();
			getCurChallMan().disposeGui();
		}
		gui.showMenu("MainMenu");

	}
}